package MAIN;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import java.security.PublicKey;
import sun.security.x509.CertAndKeyGen;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.PKIXCertPathValidatorResult;
import java.security.cert.PKIXParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import sun.security.x509.AlgorithmId;
import sun.security.x509.CertAndKeyGen;
import sun.security.x509.CertificateAlgorithmId;
import sun.security.x509.CertificateIssuerName;
import sun.security.x509.CertificateSerialNumber;
import sun.security.x509.CertificateSubjectName;
import sun.security.x509.CertificateValidity;
import sun.security.x509.CertificateVersion;
import sun.security.x509.CertificateX509Key;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;
//CERTIFICATE AUTHORITY: VERISIGN
public class usc_Certificate 
{
    public static PublicKey pubKey =  null;
    public static PrivateKey privKey =  null;
    public static final String commonName = "SERVER"; //~CN
    public static final String organizationalUnit = "12HC-IT";//~OU
    public static final String organization = "Khoa Hoc Tu Nhien";//~O
    public static final String city = "HCM";//~L
    public static final String state = "HCM";//~ST
    public static final String country = "VN";//~C
    public static final long validity = 1096; // 3 years
    public static final String alias = "FIT";
    public static final char[] keyPass = "changeit".toCharArray();//the password to protect the key
    
    public static X509Certificate generateCertificate(
            String dn, KeyPair pair, int days, String algorithm)
    throws GeneralSecurityException, IOException
    {
        /*http://stackoverflow.com/questions/1615871/creating-an-x509-certificate-in-java-without-bouncycastle
        * Create a self-signed X.509 Certificate
        * @param dn the X.509 Distinguished Name, eg "CN=Test, L=London, C=GB"
        * @param pair the KeyPair
        * @param days how many days from now the Certificate is valid for
        * @param algorithm the signing algorithm, eg "SHA1withRSA"
        */ 
      PrivateKey privkey = pair.getPrivate();
      X509CertInfo info = new X509CertInfo();
      Date from = new Date();
      Date to = new Date(from.getTime() + days * 86400000l);
      CertificateValidity interval = new CertificateValidity(from, to);
      BigInteger sn = new BigInteger(64, new SecureRandom());
      X500Name owner = new X500Name(dn);

      info.set(X509CertInfo.VALIDITY, interval);
      info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
      info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
      info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
      info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
      info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
      AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
      info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));

      // Sign the cert to identify the algorithm that's used.
      X509CertImpl cert = new X509CertImpl(info);
      cert.sign(privkey, algorithm);

      // Update the algorith, and resign.
      algo = (AlgorithmId)cert.get(X509CertImpl.SIG_ALG);
      info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo);
      cert = new X509CertImpl(info);
      cert.sign(privkey, algorithm);
      return cert;
    }   
    
    public static void createCertificate(String fileName) throws Exception
    {
        KeyPair kp = new KeyPair(pubKey, privKey);
        String dn = "";
        dn+= "CN=" + commonName + ", ";
        dn+= "OU=" + organizationalUnit + ", ";
        dn+= "O=" + organization + ", ";
        dn+= "L=" + city +", ";
        dn+= "C=" + country + "";
        X509Certificate cert = generateCertificate(dn, kp, 60, "SHA256WithRSA");
        FileOutputStream os = new FileOutputStream(fileName);
        os.write(cert.getEncoded());
        os.close();  
        //SHA1withDSA,SHA1withRSA,SHA256withRSA is Sig algo supported by Java platform.
    }
    
    public static void validateCertificate(String certFileName)
    {
        try
        {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            FileInputStream is = new FileInputStream(new File(certFileName));
            Certificate cert = cf.generateCertificate(is);
            List mylist = new ArrayList();
            mylist.add(cert);	    
            CertPath cp = cf.generateCertPath(mylist);
            Certificate trust = cert;	    
            TrustAnchor anchor = new TrustAnchor((X509Certificate) trust, null);
            PKIXParameters params = new PKIXParameters(Collections.singleton(anchor));
            params.setRevocationEnabled(false);
            CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
            /*
            PKIXCertPathValidatorResult represents the successful result of the PKIX certification path validation algorithm.
            Instances of PKIXCertPathValidatorResult are returned by the validate method of CertPathValidator objects implementing the PKIX algorithm.
            */
            PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult) cpv.validate(cp, params);
            System.out.println(result);
        }
        catch(Exception ex)
        {
            System.out.println("Invalid Input!!!");
        }
        
    }
    
    public static boolean validateCertificate(Certificate _cer)
    {
        boolean f = false;
        try
        {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            Certificate cert = _cer;
            List mylist = new ArrayList();
            mylist.add(cert);	    
            CertPath cp = cf.generateCertPath(mylist);
            Certificate trust = cert;	    
            TrustAnchor anchor = new TrustAnchor((X509Certificate) trust, null);
            PKIXParameters params = new PKIXParameters(Collections.singleton(anchor));
            params.setRevocationEnabled(false);
            CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
            /*
            PKIXCertPathValidatorResult represents the successful result of the PKIX certification path validation algorithm.
            Instances of PKIXCertPathValidatorResult are returned by the validate method of CertPathValidator objects implementing the PKIX algorithm.
            */
            PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult) cpv.validate(cp, params);
            //System.out.println(result);
            f = true;
        }
        catch(Exception ex)
        {
            System.out.println("Invalid Input!!!");
        }
        return f;
    }
        
    public static void main(String[] args) throws Exception
    {
        usc_RSAKeyPair.PUBLIC_KEY_FILE = "public.key";
        pubKey = usc_RSAKeyPair.readPublicKey();
        usc_RSAKeyPair.PRIVATE_KEY_FILE = "private.key";
        privKey = usc_RSAKeyPair.readPrivateKey();
        //System.out.println(pubKey);
        //System.out.println(privKey);
        //createCertificate("resource/GUEST.cer");
        
        //Read Certificate file
        FileInputStream is = new FileInputStream(new File("SERVER.cer"));
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        Certificate cert = cf.generateCertificate(is);
        //System.out.println(cert);
        validateCertificate(cert);
        
        //Validate Certificate file
        //validateCertificate("SERVER.cer");
        
    }
    
    
}
